home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / c_news / 11 / filechk.c < prev    next >
Text File  |  1988-08-14  |  11KB  |  400 lines

  1.     /* filechk.c  --  Disk file integrity checker.
  2.                   Reads all files on disk in current directory and in
  3.                   lower level subdirectories to verify readability and
  4.                   file size.
  5.  
  6.     by Arnold Cherdak, 8/11/88, Turbo C, Version 1.5
  7.  
  8.                 RELEASED TO THE PUBLIC DOMAIN
  9.  
  10. */
  11. #include <stdio.h>
  12. #include <dir.h>
  13. #include <dos.h>
  14. #include <fcntl.h>
  15. #include <sys\stat.h>
  16.  
  17. #define NOT_ENUFF_SPACE "\nINSUFFICIENT MEMORY SPACE!\n"
  18. #define FILECHK "FILECHK"
  19. #define BUFFER_SIZE 0x2000
  20. #define BAD_FILE_SIZE ": FILE SIZE IS WRONG!"
  21. #define PATH_SIZE 128
  22. #define TRUE 0xffffu
  23. #define FALSE 0u
  24. #define TITLE "\nFILECHK version 1.0 by Arnold Cherdak, all rights reserved"
  25. #define HEADER "\nFile Name      Size      Date      Time     Attributes"
  26.  
  27. /***************************************************************************
  28.     In the DOS directory entry, DOS time and date parameters are bit strings
  29.     that are to be interpreted as follows:
  30.  
  31.           bits   15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
  32.           TIME    h  h  h  h  h  m  m  m  m  m  m  x  x  x  x  x
  33.           DATE    y  y  y  y  y  y  y  M  M  M  M  d  d  d  d  d
  34.  
  35.      where:
  36.         h is the binary number of hours (0-23)
  37.         m is the binary number of minutes (0-59)
  38.         x is the binary number of two-second increments (0-29) corresponding
  39.           to 0-58 seconds
  40.  
  41.         y is the binary year number since 1980 (0-119) corresponding to
  42.           1980-2099  ( WOW! Think this program/operating system will be around
  43.                      ( that long?
  44.         M is the binary number of the month (1-12)
  45.         d is the binary number of the day of the month (1-31)
  46.  
  47.    The attribute byte is a bit field with interpretation as follows:
  48.  
  49.         BIT   MEANING IF SET TO 1
  50.          0       read-only
  51.          1       hidden
  52.          2       system file
  53.          3       volume label
  54.          4       subdirectory file
  55.          5       archive bit
  56.          6       (reserved -- not used)
  57.          7       (reserved -- not used)
  58.  
  59. ****************************************************************************/
  60.  
  61. struct DOS_TIME                /* bit field definitions for time */
  62.     {
  63.     unsigned twosecs:5;    /* NOTE: LSB first */
  64.     unsigned minute:6;
  65.     unsigned hour:5;
  66.     };
  67.  
  68. struct DOS_DATE                /* bit field definitions for date */
  69.     {
  70.     unsigned day:5;
  71.     unsigned month:4;
  72.     unsigned year:7;
  73.     };
  74.  
  75. struct DOS_ATTRIB              /* bit field definitions for attributes */
  76.     {
  77.     unsigned R :1;  /* read only */
  78.     unsigned H :1;  /* hidden    */
  79.     unsigned S :1;  /* system    */
  80.     unsigned V :1;  /* volume label */
  81.     unsigned D :1;  /* subdirectory */
  82.     unsigned A :1;  /* archive bit */
  83.     unsigned yy:2;  /* reserved */
  84.     unsigned xx:8;  /* filler, high-order 8-bits to make a full integer */
  85.     };
  86.  
  87. struct STACK_NODE
  88.     {
  89.     char path[PATH_SIZE];
  90.     int attribs;
  91.     struct ffblk dta;
  92.     struct STACK_NODE *next;     /* double-linked list */
  93.     struct STACK_NODE *previous;
  94.     };
  95.  
  96.  
  97. /**************************************************************************/
  98.                   void main(int argc, char *argv[])
  99. /**************************************************************************/
  100. {
  101. int j,files,ndirs,subdirs,handle,amount,retn,nfiles,nbrfiles,nerrs,flag;
  102. int helpmax,i;
  103. unsigned DOption;
  104. long total,grand_total,dir_total;
  105. char attr[6],*buffer,thisdir[PATH_SIZE],c;
  106. struct STACK_NODE *dir = NULL;
  107. union
  108.     {
  109.     struct DOS_DATE date;
  110.     struct DOS_TIME time;
  111.     struct DOS_ATTRIB attrib;
  112.     int value;
  113.     } entry;
  114.  
  115. char *help[] = {
  116. "\n\nDisk File Integrity Checker:  Reads all files on a disk or in",
  117. "\none or more (sub)directories to verify that the directory entry",
  118. "\nfor each file is correct and that the file is readable.",
  119. "\n\nUsage:  FILECHK [-D] [-H] [-?] [directoryname]",
  120.   "\n  Default operation (without command line entries) causes FILECHK",
  121.   "\n  to read all files in the current directory and all files in",
  122.   "\n  subdirectories below the current directory.",
  123. "\n\n  -D option causes FILECHK to process files in the current directory,",
  124.   "\n  only.",
  125. "\n\n  -H and -? options provide the help screen (this one).",
  126. "\n\n  The presence of a string, 'directoryname', causes FILECHK to begin",
  127.   "\n  processing in the directory having the name, 'directoryname'.\n"};
  128.  
  129.     helpmax = 12;  /* there are 12 lines in the help screen */
  130.  
  131.     /* print program header */
  132.     printf(TITLE);
  133.  
  134.     /* allocate a file buffer */
  135.     if((buffer = (char *) malloc(BUFFER_SIZE)) == NULL)
  136.         {
  137.         printf(NOT_ENUFF_SPACE);
  138.         exit(1);
  139.         }
  140.  
  141.     /* allocate a root directory node */
  142.     if((dir = (struct STACK_NODE *) calloc(1, sizeof(struct STACK_NODE))) == NULL)
  143.         {
  144.         printf(NOT_ENUFF_SPACE);
  145.         exit(1);
  146.         }
  147.     dir->previous = NULL;
  148.     dir->next = NULL;
  149.  
  150.     /* Get current working directory. */
  151.     if(getcwd(thisdir, PATH_SIZE) == NULL)
  152.         {
  153.         printf("\n");
  154.         perror(FILECHK);
  155.         exit(1);
  156.         }
  157.     strcpy(dir->path, thisdir);
  158.  
  159.     /* See if there are any command line parameters */
  160.     DOption = FALSE;
  161.     if(argc > 1)
  162.         {
  163.         /* find switches first */
  164.         for(j=1;j<argc;j++)
  165.             if(argv[j][0] == '-' || argv[j][0] == '/')
  166.                 if((c = toupper(argv[j][1])) == 'D')
  167.                     DOption = TRUE;
  168.                 else if(c == 'H' | c == '?')
  169.                     {
  170.                     for(i=0;i<helpmax;i++)
  171.                         printf(help[i]);
  172.                     exit(0);
  173.                     }
  174.  
  175.         /* Now see if this is to take place in some other directory */
  176.         for(j=1;j<argc;j++)
  177.             if(argv[j][0] != '-' && argv[j][0] != '/')
  178.                 {
  179.                 strcpy(dir->path,argv[j]);
  180.                 if(chdir(dir->path) < 0)
  181.                     {
  182.                     perror(FILECHK);
  183.                     exit(1);
  184.                     }
  185.                 break;
  186.                 }
  187.         }
  188.  
  189.     /* Set up search criteria.  These are file attributes defined in
  190.        header file, dos.h
  191.     */
  192.     files = FA_RDONLY | FA_HIDDEN | FA_SYSTEM | FA_ARCH;
  193.     subdirs = FA_DIREC;
  194.     dir->attribs = files;
  195.     flag = files;
  196.  
  197.     /* Get the first file. */
  198.     if((retn = findfirst("*.*", &(dir->dta), dir->attribs)) != 0)
  199.         {
  200.         perror(FILECHK);
  201.         exit(1);
  202.         }
  203.  
  204.     /* print path */
  205.     printf("\n\nSTARTING AT: %s",dir->path);
  206.  
  207.     /* print file listing header */
  208.     printf(HEADER);
  209.  
  210.     /* Now, print a structured directory listing and then examine the file.
  211.        Repeat this for all files in the current and lower subdirectories.
  212.     */
  213.  
  214.     ndirs = 1;
  215.     nfiles = nbrfiles = nerrs = 0;
  216.     grand_total = dir_total = 0L;
  217.     while(TRUE)
  218.         {
  219.         if(retn == -1)
  220.             /* at end */
  221.             {
  222.             if(dir->previous == NULL && dir->attribs == subdirs)
  223.                 /* all done */
  224.                 {
  225.                 printf("\n\n%d Files Processed in %d (Sub)Directories",nfiles,ndirs);
  226.                 printf("\n%ld Characters Processed",grand_total);
  227.                 printf("\n%d Errors Detected\n",nerrs);
  228.                 chdir(thisdir);
  229.                 exit(0);
  230.                 }
  231.             else if(dir->attribs == subdirs)
  232.                 /* go back to next higher level subdirectory */
  233.                 {
  234.                 dir = dir->previous;
  235.                 free(dir->next);
  236.  
  237.                 /* Change back to old subdirectory */
  238.                 if(chdir(dir->path) < 0)
  239.                     {
  240.                     perror(FILECHK);
  241.                     exit(1);
  242.                     }
  243.  
  244.                 /* Get the next file. */
  245.                 retn = findnext(&(dir->dta));
  246.                 }
  247.             else /* attribs == files */
  248.                 {
  249.                 dir->attribs = subdirs;
  250.                 flag = subdirs;
  251.  
  252.                 printf("\nThis Directory Total Files Processed = %d",nbrfiles);
  253.             printf("\nThis Directory Total Characters Processed = %ld",dir_total);
  254.                 dir_total = 0L;
  255.                 nbrfiles = 0;
  256.  
  257.                 if(DOption == TRUE)
  258.                     retn = -1;
  259.                 else
  260.                     /* Get the first subdirectory. */
  261.                     retn = findfirst("*.*", &(dir->dta), dir->attribs);
  262.                 }
  263.             }
  264.         else
  265.             /* not at end of current subdirectory */
  266.             {
  267.             /* This is NOT a subdirectory. */
  268.             if(!(dir->dta.ff_attrib & FA_DIREC) && flag == files)
  269.                 {
  270.                 /* We are not looking for subdirectories here -- this is needed
  271.                    because DOS will return ALL files even though we ask
  272.                    only for subdirs.  See DOS call 21h, function 4eh.
  273.  
  274.                    Print directory data.
  275.                 */
  276.                printf("\n%-12s",dir->dta.ff_name);
  277.                printf("%8ld",dir->dta.ff_fsize);
  278.  
  279.                 /* set up date */
  280.                 entry.value = dir->dta.ff_fdate;
  281.  
  282.                 /* now print the date */
  283.                 printf("  %2d-%02d-%2d",entry.date.month, entry.date.day,
  284.                   entry.date.year + 80);
  285.  
  286.                 /* set up time */
  287.                 entry.value = dir->dta.ff_ftime;
  288.  
  289.                 /* now print the file time */
  290.                 printf("  %2d:%02d:%02d",entry.time.hour, entry.time.minute,
  291.                   entry.time.twosecs * 2);
  292.  
  293.                 /* set up attributes */
  294.                 entry.value = dir->dta.ff_attrib;
  295.  
  296.                 /* now print the attributes */
  297.                 attr[0] = '\0';
  298.                 if (entry.attrib.R == 1) strcat(attr,"R");
  299.                 if (entry.attrib.H == 1) strcat(attr,"H");
  300.                 if (entry.attrib.S == 1) strcat(attr,"S");
  301.                 if (entry.attrib.D == 1) strcat(attr,"D");
  302.                 if (entry.attrib.A == 1) strcat(attr,"A");
  303.                 printf("    %s",attr);
  304.                 nfiles++;
  305.                 nbrfiles++;
  306.  
  307.                 /* Now verify the file by opening it and reading it. */
  308.                 if((handle = open(dir->dta.ff_name, O_RDONLY | O_BINARY)) < 0)
  309.                     {
  310.                     /* error on open */
  311.                     perror("");
  312.                     nerrs++;
  313.                     }
  314.                 else
  315.                     {
  316.                     total = 0;
  317.                     while((amount = read(handle, buffer, BUFFER_SIZE)) > 0)
  318.                         total += amount;
  319.  
  320.                     if(amount < 0)
  321.                         {
  322.                         perror("");
  323.                         nerrs++;
  324.                         }
  325.  
  326.                     if(total != dir->dta.ff_fsize)
  327.                         {
  328.                         printf(BAD_FILE_SIZE);
  329.                         nerrs++;
  330.                         }
  331.  
  332.                     grand_total += total;
  333.                     dir_total += total;
  334.                     close(handle);
  335.                     }
  336.  
  337.                 /* Now get the next directory entry */
  338.                 retn = findnext(&(dir->dta));
  339.  
  340.                 } /* end: if file is not a subdirectory... */
  341.  
  342.             else if(strcmp(dir->dta.ff_name,".") != 0 &&
  343.                  strcmp(dir->dta.ff_name,"..") != 0 &&
  344.                  (dir->dta.ff_attrib & subdirs))
  345.                 /* file IS a proper subdirectory */
  346.                 {
  347.  
  348.                 /* Change directory to go to the new subdirectory */
  349.                 if(chdir(dir->dta.ff_name) < 0)
  350.                     {
  351.                     perror(FILECHK);
  352.                     exit(1);
  353.                     }
  354.  
  355.                 /* Allocate a stack node. */
  356.                 if((dir->next = (struct STACK_NODE *)
  357.                               calloc(1, sizeof(struct STACK_NODE))) == NULL)
  358.                     {
  359.                     printf(NOT_ENUFF_SPACE);
  360.                     exit(1);
  361.                     }
  362.  
  363.                 /* push it on the stack */
  364.                 dir->next->previous = dir;
  365.                 dir = dir->next;
  366.  
  367.                 /* Get current working directory. */
  368.                 if(getcwd(dir->path, PATH_SIZE) == NULL)
  369.                     {
  370.                     printf("\n");
  371.                     perror(FILECHK);
  372.                     exit(1);
  373.                     }
  374.  
  375.                 /* print path */
  376.                 printf("\n\nSUBDIRECTORY: %s",dir->path);
  377.  
  378.                 /* print file listing header */
  379.                 printf(HEADER);
  380.  
  381.                 /* count directories */
  382.                 ndirs++;
  383.  
  384.                 /* Get the first file. */
  385.                 dir->attribs = files;
  386.                 flag = files;
  387.                 retn = findfirst("*.*", &(dir->dta), dir->attribs);
  388.  
  389.                 } /* end: if file IS a proper subdirectory */
  390.             else
  391.                 /* not "." or ".." - not a proper subdirectory */
  392.                 /* get next */
  393.                 retn = findnext(&(dir->dta));
  394.  
  395.             } /* end: else - not at end of current subdirectory */
  396.  
  397.         } /* end: while(TRUE) */
  398.  
  399. } /* end: main */
  400.